package com.soufang.soufangdemo.base;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.soufang.soufangdemo.entity.Role;
import com.soufang.soufangdemo.entity.User;
import com.soufang.soufangdemo.repository.RoleRepository;
import com.soufang.soufangdemo.repository.UserRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import java.util.List;

@Configuration // 声明配置类
@EnableWebSecurity // 启用 spring security
public class WebSecurityConfig {
    private UserRepository userRepository;
    private ObjectMapper mapper;
    private RoleRepository roleRepository;

    public WebSecurityConfig(UserRepository userRepository, ObjectMapper mapper, RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.mapper = mapper;
        this.roleRepository = roleRepository;
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(registry -> {
                    // ant pattern 是一种 URL 匹配表达式
                    // /admin/a /admin/a/b /admin
                    registry.antMatchers("/api/admin/**").hasRole("admin") // 管理员才能访问管理员下面的东西
                            .antMatchers("/api/users/**").authenticated()// 所有登陆过后的用户都能访问 /api/users 下面的资源
                            .anyRequest().permitAll(); // 其他资源全都不需要登陆
                })
                .formLogin(configurer -> configurer.loginProcessingUrl("/api/sessions")
                        .successHandler((request, response, authentication) -> {
                            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                            response.setCharacterEncoding("UTF-8");
                            response.getWriter().write(mapper.writeValueAsString(ApiResponse.success()));
                            response.getWriter().flush();
                        })
                        .failureHandler((request, response, exception) -> {
                            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                            response.setCharacterEncoding("UTF-8");
                            response.getWriter().write(mapper.writeValueAsString(
                                    ApiResponse.error(Status.INVALID_USERNAME_OR_PASSWORD)));
                            response.getWriter().flush();
                        }))
                .userDetailsService(userDetailsService())
                .csrf().disable() // 禁用防御跨站攻击 ，因为 AJAX API 提交登陆的方式没有跨站攻击问题
                .build();
    }

    @Bean
    PasswordEncoder encoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    UserDetailsService userDetailsService() {
        return username -> {
            User user;
            if ((user = userRepository.findByName(username)) == null
                    && (user = userRepository.findByEmail(username)) == null
                    && (user = userRepository.findByPhoneNumber(username)) == null) {
                throw new UsernameNotFoundException("用户名密码错误");
            }
            List<Role> roles = roleRepository.findAllByUserId(user.getId());
            return new SecurityUser(user, roles);
        };
    }
}
